const std = @import("std");
const fmt = std.fmt;
const builtin = std.builtin;
const set = std.bit_set;

const natural = enum {
    f8,
    f16,
    f32,
    f64,
    f128,
};

const G = 6.674E-11;
const FOURTHIRDS = 1.3333333333333;
const PI = 3.141592653589793;
pub fn vector2(comptime T: type) type {
    return struct {
        const Self = @This();
        x: T,
        y: T,
        den: T = 1.0,
        rad: T,

        pub fn magnitude(self: *Self) T {
            return std.math.sqrt(self.x * self.x + self.y * self.y);
        }

        pub fn mass(self: *Self) T {
            return self.vol() * self.den;
        }

        pub fn vol(self: *Self) T {
            return PI * self.rad * self.rad;
        }

        pub fn inverse(v: T) T {
            return (@as(T, 1.0) / v);
        }

        pub fn force(self: *Self, b: *vector2(T), dist: T) T {
            return G * @divExact(self.mass() * b.mass(), dist);
        }

        pub fn delta(a: vector2(T), b: vector2(T)) vector2(T) {
            return .{
                .x = a.x - b.x,
                .y = a.y - b.y,
                .rad = @divExact(a.rad + b.rad, 2.0),
            };
        }
    };
}

pub fn vector3(comptime T: type) type {
    return struct {
        const Self = @This();
        x: T,
        y: T,
        z: T,
        den: T = 1.0,
        rad: T,

        pub fn magnitude(self: *Self) T {
            return std.math.sqrt(self.x * self.x + self.y * self.y + self.z * self.z);
        }

        pub fn mass(self: *Self) T {
            return self.vol() * self.den;
        }

        pub fn vol(self: *Self) T {
            return FOURTHIRDS * PI * self.rad * self.rad * self.rad;
        }

        pub fn inverse(v: T) T {
            return (@as(T, 1.0) / v);
        }

        pub fn force(self: *Self, b: *vector3(T), dist: T) T {
            return G * @divExact(self.mass() * b.mass(), dist);
        }

        pub fn delta(a: vector3(T), b: vector3(T)) vector3(T) {
            return .{
                .x = a.x - b.x,
                .y = a.y - b.y,
                .z = a.z - b.z,
                .rad = @divExact(a.rad + b.rad, 2.0),
            };
        }
    };
}

test "vector 3" {
    const v = vector3(f64);
    var c: v = .{
        .x = 3.0,
        .y = 3.0,
        .z = 3.0,
        .rad = 1.0,
    };
    var d: v = .{
        .x = 0.0,
        .y = 0.0,
        .z = 0.0,
        .rad = 5.0,
    };

    var e: v = v.delta(c, d);
    var dist = e.magnitude();
    var force = c.force(&d, dist);
    std.debug.print(" FORCE BETWEEN {any} \n", .{force});
}
